#include <windows.h>
#include <windowsx.h>
#include "RiderEngine.h"
#include "component/BasicComponents.h"
#include "bx/thread.h"
#include "bgfx/platform.h"
#include "TimeUtil.h"
#include "LogUtil.h"
#include <cmath>

#define WIDTH 1024
#define HEIGHT 720

using namespace NS_RIDER;

HWND window = nullptr;
bool m_render_finished = false;

struct RenderThreadEntry {
    static int32_t render(bx::Thread* _thread, void* _userData) {
        RenderConfig config{WIDTH, HEIGHT, window, true};
        RiderEngine* engine = new RiderEngine(config);
        SceneManager& scenes = engine->GetScenes();
        Scene* mainScene = scenes.CreateScene();
        Camera camera = {
                {0, 0, WIDTH, HEIGHT},
                {0.f,0.f,3.5}
        };
        mainScene->SetCamera(camera);
        mainScene->SetDebugInfo(DebugInfo{1, 1});

        Texture2D specularTexture = engine->GetResources().CreateOrGetTexture("../platform/Windows/demo/container2_specular.png");

        Entity entity = mainScene->CreatePrimitiveEntity(PrimitiveType::Box, "box1");
        entity.component<Transform>()->translation = {0.6, 0.6, 0};
        entity.component<Transform>()->rotation = Quaternion::FromEuler(0, 45, 0);
        Material material = engine->GetResources().CreateTextureMaterial("../platform/Windows/demo/container2.png");
        material.specular_texture = specularTexture;
        entity.component<MeshRenderModel>()->material = material;
        mainScene->AddEntity(entity);

        Entity entity2 = mainScene->CreatePrimitiveEntity(PrimitiveType::Capsule, "box2");
        entity2.component<Transform>()->translation = {1.5, -1, 0};
        Material material2 = engine->GetResources().CreateTextureMaterial("../platform/Windows/demo/container2.png");
        material2.specular_texture = specularTexture;
        entity2.component<MeshRenderModel>()->material = material2;
        mainScene->AddEntity(entity2);

        Entity light = mainScene->CreatePrimitiveEntity(PrimitiveType::Sphere, "light1");
        Light component = {LightType::Point, Colors::White};
        component.range = 10;
        component.strength = 1.5;
        light.assign<Light>(component);
        light.component<Transform>()->translation = {-1, 0.8, 0};
        light.component<Transform>()->rotation = {0.3, 0.3, 0.3};
        mainScene->AddEntity(light);

        scenes.LoadScene(mainScene);


        UInt64 start = 0;
        while (!m_render_finished) {
            start = TimeUtil::MilliTime();
            engine->Update();
            UInt64 through = TimeUtil::MilliTime() - start;
            entity.component<Transform>()->rotation.AddRotation(0, 0.1, 0);
            UInt64 fps = through == 0 ? 1000 : 1000 / through;
            char buf[10] = {0};
            sprintf(buf, "FPS: %lld", fps);
            mainScene->SetDebugInfo(DebugInfo{1, 1, 0x0f, buf});
        }
        return 0;
    }
};

LRESULT process(HWND _hwnd, UINT _id, WPARAM _wparam, LPARAM _lparam) {
    switch (_id) {
        case WM_CLOSE:
            m_render_finished = true;
            DestroyWindow(_hwnd);
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        case WM_QUIT:
            m_render_finished = true;
            // Don't process message. Window will be destroyed later.
            return 0;
    }
    return DefWindowProcW(_hwnd, _id, _wparam, _lparam);
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd) {

#ifdef ENABLE_LOG
    freopen("test.txt", "w", stdout);
#endif

    SetDllDirectoryA(".");

    HINSTANCE instance = (HINSTANCE)GetModuleHandle(NULL);

    WNDCLASSEXW wnd;
    bx::memSet(&wnd, 0, sizeof(wnd) );
    wnd.cbSize = sizeof(wnd);
    wnd.style = CS_HREDRAW | CS_VREDRAW;
    wnd.lpfnWndProc = process;
    wnd.hInstance = instance;
    wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
    wnd.lpszClassName = L"Rider3D";
    wnd.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    RegisterClassExW(&wnd);

    window = CreateWindowExA(
            WS_EX_ACCEPTFILES
            , "Rider3D"
            , "Rider3D"
            , WS_OVERLAPPEDWINDOW|WS_VISIBLE
            , 0
            , 0
            , WIDTH
            , HEIGHT
            , NULL
            , NULL
            , instance
            , 0
    );

    RenderThreadEntry render_thread;
    bx::Thread thread;
    thread.init(RenderThreadEntry::render, &render_thread);

    MSG msg;
    msg.message = WM_NULL;
    while (!m_render_finished) {
        while (PeekMessageW(
                &msg, NULL, 0U, 0U, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
    }
    thread.shutdown();
    return thread.getExitCode();
}